package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.dto.NursingPlanDto;
import com.zzyl.entity.NursingPlan;
import com.zzyl.mapper.NursingPlanMapper;
import com.zzyl.service.NursingPlanProjectService;
import com.zzyl.service.NursingPlanService;
import com.zzyl.vo.NursingPlanProjectVo;
import com.zzyl.vo.NursingPlanVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class NursingPlanServiceImpl implements NursingPlanService {

    @Autowired
    private NursingPlanMapper nursingPlanMapper;

    @Autowired
    private NursingPlanProjectService nursingPlanProjectService;

    /**
     * 分页查询护理计划
     *
     * @param pageNum  请求的页码
     * @param pageSize 每页显示的数量
     * @param name     护理计划的名称，可选查询条件
     * @param status   护理计划的状态，可选查询条件
     * @return 返回分页查询结果的响应对象
     */
    @Override
    public PageResponse<NursingPlanVo> findByPage(Integer pageNum, Integer pageSize, String name, Integer status) {
        // 开启分页
        PageHelper.startPage(pageNum, pageSize);
        // 调用mapper查询，根据名称和状态进行过滤
        List<NursingPlanVo> vo = nursingPlanMapper.findByPage(name, status);
        // 将查询结果转换为分页对象
        Page<NursingPlanVo> page = (Page<NursingPlanVo>)vo;
        // 构造并返回分页响应对象
        return PageResponse.of(page,NursingPlanVo.class);
    }

    /**
     * 根据护理计划ID查询详细的护理计划信息。
     *
     * @param planId 护理计划的ID，用于查询特定的护理计划。
     * @return 返回一个包含护理计划详细信息的Vo对象，其中包括护理计划的项目列表。
     */
    @Override
    public NursingPlanVo findById(Long planId) {
        // 根据ID查询护理计划表，获取护理计划的详细信息
        NursingPlanVo nursingPlanVo = nursingPlanMapper.selectById(planId);

        // 根据护理计划ID查询护理计划项目中间表，获取所有关联的护理项目
        List<NursingPlanProjectVo> vo = nursingPlanProjectService.findByPlanId(planId);

        // 将查询到的护理项目集合封装到护理计划Vo对象中
        nursingPlanVo.setProjectPlans(vo);

        // 返回护理计划Vo对象
        return nursingPlanVo;
    }

    /**
     * 根据id修改护理计划及其关联项目。
     *
     * @param dto 护理计划传输对象，包含需要更新的护理计划信息及关联项目。
     *
     * 该方法主要步骤如下：
     * 1. 实现属性从传输对象到实体对象的拷贝。
     * 2. 更新护理计划表中的信息。
     * 3. 根据护理计划id，删除护理计划与项目关联的中间表数据。
     * 4. 新增护理计划与项目关联的中间表数据。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateById(NursingPlanDto dto) {
        //1.属性拷贝
        NursingPlan nursingPlan = BeanUtil.toBean(dto, NursingPlan.class);
        //2.修改计划表
        nursingPlanMapper.update(nursingPlan);
        //3.根据计划表的id,删除中间表的数据
        nursingPlanProjectService.deleteByPlanId(nursingPlan.getId());
        //4.新增中间表
        nursingPlanProjectService.save(dto.getProjectPlans(),nursingPlan.getId());
    }

    /**
     * 新增保存护理计划。
     *
     * @param dto 护理计划的传输对象，包含了需要保存的护理计划的详细信息。
     *
     * 本方法通过以下步骤完成护理计划的新增保存：
     * 1. 实例化一个NursingPlan对象，并通过BeanUtil将dto中的信息拷贝到该对象中。
     * 2. 设置NursingPlan对象的状态为1（代表激活状态）。
     * 3. 调用nursingPlanMapper的save方法，将NursingPlan对象保存到数据库中。
     * 4. 调用nursingPlanProjectService的save方法，保存护理计划与项目之间的关系。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(NursingPlanDto dto) {
        // 1.属性拷贝并设置状态
        NursingPlan nursingPlan = BeanUtil.toBean(dto, NursingPlan.class);
        nursingPlan.setStatus(1);
        // 2.新增计划
        nursingPlanMapper.save(nursingPlan);
        // 3.新增计划与项目的关联
        nursingPlanProjectService.save(dto.getProjectPlans(),nursingPlan.getId());
    }

    /**
     * 根据计划id删除计划及其相关项目。该方法首先会删除计划表中的记录，然后删除与该计划相关联的中间表记录。
     *
     * @param planId 计划的唯一标识符，用于指定要删除的计划。
     * @return 无返回值。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long planId) {
        // 删除计划表中的记录
        nursingPlanMapper.deleteById(planId);
        // 删除与该计划相关联的中间表记录
        nursingPlanProjectService.deleteByPlanId(planId);
    }

    /**
     * 更新护理计划的状态。
     *
     * @param id 护理计划的唯一标识符，类型为Long。
     * @param status 护理计划的新状态，类型为Integer。
     *
     * 此方法通过查询护理计划的详细信息，更新其状态，并将更新后的护理计划保存到数据库中。
     */
    @Override
    public void updateStatus(Long id, Integer status) {
        // 创建一个新的护理计划实例，用于更新状态
        NursingPlan nursingPlan = new NursingPlan();
        nursingPlan.setStatus(status); // 设置新的状态
        nursingPlan.setId(id); // 设置护理计划的ID
        nursingPlanMapper.update(nursingPlan); // 调用mapper层执行更新操作
    }
}
